package com.panfeng.xcloud.boss.provider.assets.aop;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.panfeng.xcloud.common.core.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Aspect
@Component
@Slf4j
public class CacheHandlerAspect {

    @Autowired
    private RedisTemplate redisTemplate;

    @Around("@annotation(com.panfeng.xcloud.boss.provider.assets.aop.CacheHandler)")
    public Object cacheProcess(ProceedingJoinPoint jp) throws Throwable {
        Class<?> targetClz = jp.getTarget().getClass();
        String methodName = jp.getSignature().getName();
        if (!(jp.getSignature() instanceof MethodSignature)) {
            log.warn("该方法接口无法启用缓存功能: {}", jp.getSignature().toLongString());
            return jp.proceed();
        }
        MethodSignature methodSign = (MethodSignature) jp.getSignature();
        CacheHandler cacheHandler = methodSign.getMethod().getAnnotation(CacheHandler.class);
        if (null == cacheHandler) {
            log.info("该方法接口无法启用缓存功能: {}", jp.getSignature().toLongString());
            return jp.proceed();
        }
        int expire = cacheHandler.expire() > 0 ? cacheHandler.expire() : 200;
        String cacheKey = buildCacheKey(cacheHandler,targetClz, methodName, jp.getArgs());
        Object resultVal = cacheHandler(cacheHandler, methodSign, jp, cacheKey, expire);
        return resultVal;
    }

    private String buildCacheKey(CacheHandler cacheHandler,Class targetClz, String methodName, Object[] args) {
        String keyPrefix = cacheHandler.keyPrefix();
        if(null != args && args.length > 0){
            String argsStr = JSON.toJSONString(args, SerializerFeature.IgnoreNonFieldGetter);
            return keyPrefix + targetClz.getPackage() + methodName +"."+ argsStr;
        }else{
            return keyPrefix + targetClz.getPackage() + methodName;
        }
    }

    private Object cacheHandler(CacheHandler cacheHandler, MethodSignature methodSign, ProceedingJoinPoint jp, String cacheKey, int expire) throws Throwable {
        log.info(">>> 开始执行缓存处理keyPrefix：{}-> expire:{} -> cacheKey:{} <<<",cacheHandler.keyPrefix(),cacheHandler.expire(),cacheKey);
        Class returnClazz = methodSign.getReturnType();
        Object result;
        Object cacheResultJsonString = redisTemplate.opsForValue().get(cacheKey);
        if (null == cacheResultJsonString) {
            log.info(">>> 未命中缓存，从后台查询相应的数据加载到缓存key : {}", cacheKey);
            result = jp.proceed();
            if (null != result) {
                if (ObjectUtils.isBaseType(returnClazz)) {
                    log.info(">>> 设置缓存到redis中，缓存key:{},缓存内容：{}", cacheKey, result);
                    redisTemplate.opsForValue().set(cacheKey, result, expire, TimeUnit.SECONDS);
                }else{
                    String resultJsonString = JSON.toJSONString(result);
                    log.info(">>> 设置缓存到redis中，缓存key:{},缓存内容：{}", cacheKey, resultJsonString);
                    redisTemplate.opsForValue().set(cacheKey, resultJsonString, expire, TimeUnit.SECONDS);
                }
            }
        } else {
            if (ObjectUtils.isBaseType(returnClazz)) {
                result = cacheResultJsonString;
                log.info(">>> 缓存key:{} 从缓存中获取到的值为: {} <<<",cacheKey, result);
            } else {
                JSONObject jsonObject = JSON.parseObject((String) cacheResultJsonString);
                result = JSONObject.toJavaObject(jsonObject, returnClazz);
                log.info(">>> 缓存key:{} 从缓存中获取到的值为: {} <<<",cacheKey, cacheResultJsonString);
            }
        }
        return result;
    }
}